/*
 * Main.java
 *
 * Created on 30 de Maio de 2007, 11:45
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package fakeclient;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Random;
import qvoipm.dados.Certificado;
import qvoipm.dados.Fim;
import qvoipm.dados.Inicio;
import qvoipm.dados.Pacote;
import qvoipm.dados.Qualidade;

/**
 *
 * @author rodrigo
 */
public class Main {
    
    public static final int PORTA_C = 3707;
    public static final int PORTA_Q = 3708;
    public static final int ITERACOES = 100;
    public static final GregorianCalendar inicial = new GregorianCalendar(2006, 10, 22, 4, 0);
    
    /* intervalo entre as iteracoes */
    public static final int FIELD = Calendar.HOUR;
    public static final int MIN_AMOUNT = 2;
    public static final int VAR_AMOUNT = 32;
    
    public static final int codecs[] = {
	0,	1,	2,	3,	4,	5,	6,	7,	8,	9,	10,	11,
	12,	13,	14,	15,	16,	17,	18,	19,	25,	26,	28,	31,
	32,	33,	34,	72,	73,	74,	75,	76,	96,	97,	98,	99,
	100,	101,	102,	103,	104,	105,	106,	107,	108,	109,	110,	111,
	112,	113,	114,	115,	116,	117,	118,	119,	120,	121,	122,	123,
	124,	125,	126,	127,	128,	129,	130,	131,	132,	133,	134,	135,
	136,	137};
    
    /** Creates a new instance of Main */
    private Main() {
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
	Socket socket;
	InputStream in;
	OutputStream out;
	
	/* cria pacote de qualidade para ser usado */
	Qualidade qualidade = new Qualidade();
	
	/* Cria pacote de certificado para ser usado */
	Certificado certificado = new Certificado();
	
	/* Buffers */
	byte buffCertificado[] = new byte[Certificado.SIZE];
	
	/* Buffers de IP */
	byte ipA[] = new byte[4];
	byte ipB[] = new byte[4];
	
	/* Inicia gerador de numeros aleatorios */
	Random rnd = new Random(System.currentTimeMillis());
	
	GregorianCalendar data = (GregorianCalendar)inicial.clone();
	long tempoDecorrido;
	
	try {
	    
	    for (int i = 0; i < ITERACOES; i++) {
		
		System.out.println("Iteracao " + i);
		
		/* Conecta-se com o servidor de certificado */
		System.out.println("Conectando ao servidor de certificado...");
		socket = new Socket("localhost", PORTA_C);
		
		/* Cria reader */
		in = socket.getInputStream();
		
		/* Cria writer */
		out = socket.getOutputStream();
		
		/* Cria ips aleatorios */
		rnd.nextBytes(ipA);
		rnd.nextBytes(ipB);
		
		/* cria frequencia aleatoria */
		long frequencia = 10 + Math.abs(rnd.nextLong() % 100);
		
		/* Cria pacote de inicio */
		Inicio inicio = new Inicio();
		inicio.setDataHora(data.getTime());
		inicio.setIpOrigem(InetAddress.getByAddress(ipA));
		inicio.setIpDestino(InetAddress.getByAddress(ipB));
		inicio.setFrequencia(frequencia);
		
		/* comeca cronometro */
		tempoDecorrido = System.currentTimeMillis();
		
		/* Envia pacote de destino */
		System.out.println("Enviando pacote de requisição de chamada...");
		out.write(inicio.toBytes(true));
		
		/* Recebe(aguarda) pacote de certificado */
		if (in.read() == Certificado.ID) {
		    
		    /* Le certificado */
		    in.read(buffCertificado);
		    
		    /* Seta pacote certificado */
		    certificado.fromBytes(buffCertificado, false);
		    
		    /* Captura e mostra id da chamada */
		    System.out.println("ID da chamada: " + Integer.toString(certificado.getChamada()));
		} else {
		    System.err.println("Certificado recebido invalido.");
		    /* fecha conexao */
		    in.close();
		    out.close();
		    socket.close();
		    /* sai */
		    return;
		}
		
		/* fecha conexao */
		in.close();
		out.close();
		socket.close();
		
		/* seta codec */
		int codec = codecs[Math.abs(rnd.nextInt(codecs.length))];
		
		/* Cria pacotes de qualidade */
		int numeroPacotes = 20 + Math.abs(rnd.nextInt(50));
		
		/* loop de pacotes */
		System.out.println("Enviando " + numeroPacotes + " pacotes de qualidade");
		for (int c = 0; c < numeroPacotes; c++) {
		    
		    /* Cria nova conexao com servidor de qualidade */
		    socket = new Socket("localhost", PORTA_Q);
		    
		    /* Cria writer */
		    out = socket.getOutputStream();
		    
		    /* Seta opcoes do pacote de qualidade */
		    qualidade.setAtraso(Math.abs(rnd.nextFloat()));
		    qualidade.setChamada(certificado.getChamada());
		    qualidade.setCodec(codec);
		    qualidade.setFatorR(Math.abs(rnd.nextFloat()*100.0f));
		    qualidade.setJitter(Math.abs(rnd.nextFloat()));
		    qualidade.setPerda(Math.abs(rnd.nextInt(100)));
		    
		    /* envia */
		    System.out.print(".");
		    out.write(qualidade.toBytes(true));
		    
		    /* Fecha conexao */
		    out.close();
		    socket.close();
		    
		    /* Aguarda... */
		    Thread.sleep(frequencia);
		}
		System.out.println();
		
		/* Cria nova conexao com servidor de qualidade */
		socket = new Socket("localhost", PORTA_Q);
		out = socket.getOutputStream();
		
		/* Termina cronometro */
		tempoDecorrido = System.currentTimeMillis() - tempoDecorrido;
		data.add(Calendar.MILLISECOND, (int)tempoDecorrido);
		
		/* Cria finalizacao */
		Fim fim = new Fim();
		fim.setChamada(certificado.getChamada());
		fim.setDataHora(data.getTime());
		
		System.out.println("Enviando pacote de finalização...");
		out.write(fim.toBytes(true));
		out.close();
		socket.close();
		
		/* Incrementa data */
		data.add(FIELD, MIN_AMOUNT + Math.abs(rnd.nextInt(VAR_AMOUNT)));
		
		/* Coleta lixo */
		System.gc();
	    }
	    
	} catch (UnknownHostException ex) {
	    ex.printStackTrace();
	} catch (IOException ex) {
	    ex.printStackTrace();
	} catch (InterruptedException ex) {
	    ex.printStackTrace();
	}
	
	/* Finaliza servidores */
	System.out.println("Finalizando servidores...");
	try {
	    socket = new Socket("localhost", PORTA_C);
	    out = socket.getOutputStream();
	    out.write(Pacote.TERMINAR_SERVIDOR);
	    socket.close();
	    
	    socket = new Socket("localhost", PORTA_Q);
	    out = socket.getOutputStream();
	    out.write(Pacote.TERMINAR_SERVIDOR);
	    out.close();
	    socket.close();
	} catch (UnknownHostException ex) {
	    ex.printStackTrace();
	} catch (IOException ex) {
	    ex.printStackTrace();
	}
    }
    
}
